package tenumn.energytech.registrys.pipeline;

import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.block.entity.BlockEntityType;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraftforge.common.capabilities.Capability;
import net.minecraftforge.common.util.LazyOptional;
import net.minecraftforge.energy.CapabilityEnergy;
import net.minecraftforge.energy.IEnergyStorage;

import javax.annotation.Nonnull;
import java.util.Objects;

public class WireBlockEntity extends BlockEntity {
    private final LazyOptional<IEnergyStorage> lazyOptional = LazyOptional.of(() -> new IEnergyStorage() {
        private final SimpleEnergyNetwork network = SimpleEnergyNetwork.Factory.get(WireBlockEntity.this.level);

        @Override
        public int receiveEnergy(int maxReceive, boolean simulate) {
            int energy = this.getEnergyStored();
            int diff = Math.min(500, Math.min(this.getMaxEnergyStored() - energy, maxReceive));
            if (!simulate) {
                this.network.addEnergy(WireBlockEntity.this.getBlockPos(), diff);
                if (diff != 0) {
                    WireBlockEntity.this.setChanged();
                }
            }
            return diff;
        }

        @Override
        public int extractEnergy(int maxExtract, boolean simulate) {
            int energy = this.getEnergyStored();
            int diff = Math.min(500, Math.min(energy, maxExtract));
            if (!simulate) {
                this.network.addEnergy(WireBlockEntity.this.getBlockPos(), -diff);
                if (diff != 0) {
                    WireBlockEntity.this.setChanged();
                }
            }
            return diff;
        }

        @Override
        public int getEnergyStored() {
            return Math.min(this.getMaxEnergyStored(), this.network.getNetworkEnergy(WireBlockEntity.this.getBlockPos()));
        }

        @Override
        public int getMaxEnergyStored() {
            return 1_000 * this.network.getNetworkSize(WireBlockEntity.this.getBlockPos());
        }

        @Override
        public boolean canExtract() {
            return true;
        }

        @Override
        public boolean canReceive() {
            return true;
        }
    });
    private Integer tmpEnergy = null;

    public WireBlockEntity(BlockEntityType<?> pType, BlockPos pWorldPosition, BlockState pBlockState) {
        super(pType, pWorldPosition, pBlockState);
    }

    @Nonnull
    @Override
    public <T> LazyOptional<T> getCapability(@Nonnull Capability<T> cap, Direction side) {
        boolean isEnergy = Objects.equals(cap, CapabilityEnergy.ENERGY);
        return isEnergy ? this.lazyOptional.cast() : super.getCapability(cap, side);
    }

    @Override
    public void load(@Nonnull CompoundTag compound) {
        this.tmpEnergy = compound.getInt("WireEnergy");
        super.load(compound);
    }

    @Nonnull
    @Override
    public void saveAdditional(@Nonnull CompoundTag compound) {
        SimpleEnergyNetwork network = SimpleEnergyNetwork.Factory.get(this.level);
        compound.putInt("WireEnergy", network.getSharedEnergy(this.getBlockPos()));
        super.saveAdditional(compound);
    }

    @Override
    public void onLoad() {
        if (this.level != null && !this.level.isClientSide) {
            SimpleEnergyNetwork network = SimpleEnergyNetwork.Factory.get(this.level);
            if (this.tmpEnergy != null) {
                int diff = this.tmpEnergy - network.getSharedEnergy(this.getBlockPos());
                network.addEnergy(this.getBlockPos(), diff);
                this.tmpEnergy = null;
            }
            network.enableBlock(this.getBlockPos(), this::setChanged);
        }
        super.onLoad();
    }

    @Override
    public void onChunkUnloaded() {
        if (this.level != null && !this.level.isClientSide) {
            SimpleEnergyNetwork network = SimpleEnergyNetwork.Factory.get(this.level);
            network.disableBlock(this.getBlockPos(), this::setChanged);
        }
        super.onChunkUnloaded();
    }

    @Override
    public void setRemoved() {
        if (this.level != null && !this.level.isClientSide) {
            SimpleEnergyNetwork network = SimpleEnergyNetwork.Factory.get(this.level);
            network.disableBlock(this.getBlockPos(), () ->
            {
                int diff = network.getSharedEnergy(this.getBlockPos());
                network.addEnergy(this.getBlockPos(), -diff);
                this.setChanged();
            });
        }
        super.setRemoved();
    }

}
